package com.example.plugins.routes

import com.example.*
import com.example.plugins.OrderDto
import com.example.plugins.OrderItemDto
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.transaction


data class PlaceOrderRequestDto(
    val id : Int,
    val destination: String,
    val user_name : String,
    val orderItemDto: MutableList<OrderItemDto> = mutableListOf()
) {
    data class OrderPositionDto(
        val id : Int,
        val coal_name: String,
        val distributor_name: String,
        val amountInKg: Int,
        val price: Int
    )
}

val orderRepo: OrderRepo = ExposedOrderRepo()
fun Route.ordersRouting() {
    route("/orders") {
        get {
            call.respond(HttpStatusCode.OK, orderRepo.getAll())
        }
        get("{id?}"){
            val id = call.parameters["id"]?.toLongOrNull()

            if (id == null) {
                call.respond(HttpStatusCode.BadRequest, "нет такого id")

                return@get
            }

            val order = orderRepo.getByIdOrNull(id.toInt())
            if (order == null) {
                call.respond(HttpStatusCode.NotFound)

                return@get
            }

            call.respond(HttpStatusCode.OK, message = order)
        }
        post {
            val orderPositionDto = call.receive<PlaceOrderRequestDto>()

            orderRepo.createOrder(orderPositionDto.orderItemDto, orderPositionDto.destination)

            call.respondText("Distributor has been added", status = HttpStatusCode.Created)
        }
    }
}

interface OrderRepo {
    fun getAll(): List<OrderDto>
    fun getByIdOrNull(orderid: Int): OrderDto?
    fun createOrder(items: MutableList<OrderItemDto>, destination: String)
}

class ExposedOrderRepo : OrderRepo {
    override fun getAll(): List<OrderDto> {
        return transaction {
            val r = queryOrder().toList()

            return@transaction mapToOrder(r)
        }
    }
    override fun getByIdOrNull(orderid: Int): OrderDto? {
        return transaction {
            val r = queryOrder()
                .where { Orders.id eq orderid }
                .toList()

            return@transaction mapToOrder(r).singleOrNull()
        }
    }
    override fun createOrder(items: MutableList<OrderItemDto>, destination: String) {
        return transaction {
            SchemaUtils.create(Orders)
            items.forEach { orderPosition ->

                Orders.insert {
                    it[this.destination] = destination

                }

//                OrderItems.insert {
//                    it[coalId] = orderPosition.coalId
//                    it[distributorId] = orderPosition.distributorId
//                    it[count] = orderPosition.amountInKg
//                }

            }
        }
    }

    private fun queryOrder(): Query {
        return transaction {

            Orders
                .join(
                    Users, JoinType.INNER,
                    additionalConstraint = {
                        Orders.user eq Users.id
                    }
                )
                .join(
                    OrderItems, JoinType.INNER,
                    additionalConstraint = {
                        OrderItems.order eq Orders.id
                    }
                )
                .join(
                    DistributorsToCoalMarks, JoinType.INNER,
                    additionalConstraint = {
                        DistributorsToCoalMarks.id eq OrderItems.distributorCoal
                    }
                )
                .join(
                    CoalMarks, JoinType.INNER,
                    additionalConstraint = {
                        CoalMarks.id eq DistributorsToCoalMarks.coalMarkId
                    }
                )
                .join(
                    Distributors, JoinType.INNER,
                    additionalConstraint = {
                        Distributors.id eq DistributorsToCoalMarks.distributorId
                    }
                )
                .select(
                    Orders.id,
                    Orders.destination,
                    Users.id,
                    Users.name,
                    Distributors.id,
                    Distributors.name,
                    CoalMarks.id,
                    CoalMarks.name,
                    DistributorsToCoalMarks.price,
                    OrderItems.id,
                    OrderItems.amountInKg
                ).groupBy()
        }
    }

    private fun mapToOrder(rows: List<ResultRow>): List<OrderDto> {
        val order = mutableMapOf<Int, OrderDto>()

        rows.forEach { row ->
            val dId = row[Orders.id]

            if (!order.containsKey(dId.value)) {
                order[dId.value] = OrderDto(
                    dId.value,
                    row[Orders.destination],
                    row[Users.name]
                )
            }

            order[dId.value]!!.orderItemDto.add(
                OrderItemDto(
                    id = row[OrderItems.id].value,
                    coal_name = row[CoalMarks.name],
                    distributor_name = row[Distributors.name],
                    amountInKg = row[OrderItems.amountInKg],
                    price = row[DistributorsToCoalMarks.price]
                )
            )
        }

        return order.values.toList()
    }
}